package com.houkunlin.wake.lan.scan;

import com.houkunlin.dao.PageVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;

/**
 * @author HouKunLin
 */
@Slf4j
@Service
public class NmapServiceImpl implements NmapService {
    @Async
    @Override
    public Future<PageVo<NmapVo>> doScan(String cidr) {
        try {
            final LocalDateTime startTime = LocalDateTime.now();
            final Process process = Runtime.getRuntime().exec("nmap -PR -sn " + cidr);
            final byte[] stdInput = IOUtils.toByteArray(process.getInputStream());
            final byte[] stdError = IOUtils.toByteArray(process.getErrorStream());
            final String stdInputMsg = new String(stdInput);
            final String stdErrorMsg = new String(stdError);
            final LocalDateTime endTime = LocalDateTime.now();

            final List<NmapVo> nmapVos = parseNmapVo(stdInputMsg);
            final PageVo<NmapVo> pageVo = new PageVo<>(nmapVos, 1L, nmapVos.size(), nmapVos.size(), true, true, nmapVos.isEmpty(), Collections.emptyList());
            pageVo.put("stdInputMsg", stdInputMsg);
            pageVo.put("stdErrorMsg", stdErrorMsg);
            pageVo.put("success", StringUtils.hasText(stdInputMsg));
            pageVo.put("startTime", startTime);
            pageVo.put("endTime", endTime);
            pageVo.put("duration", Duration.between(startTime, endTime).toMillis());
            return new AsyncResult<>(pageVo);
        } catch (IOException e) {
            log.error("执行扫描错误", e);
        }
        return new AsyncResult<>(null);
    }

    private List<NmapVo> parseNmapVo(final String nmapResult) {
        if (!StringUtils.hasText(nmapResult)) {
            return Collections.emptyList();
        }
        final List<NmapVo> list = new ArrayList<>();

        final String[] strings = nmapResult.replace("\r", "").split("\n");
        NmapVo curr = null;
        for (final String string : strings) {
            if (string.startsWith("Nmap scan report for ")) {
                curr = new NmapVo();
                list.add(curr);
                final int startIndex = "Nmap scan report for ".length();
                final int endIndex = string.lastIndexOf(" ");
                if (endIndex > startIndex) {
                    curr.setIp(string.substring(startIndex, endIndex));
                } else {
                    curr.setIp(string.substring(startIndex));
                }
            }
            if (curr != null && string.startsWith("Host is ")) {
                final int startIndex = "Host is ".length();
                curr.setStatus(string.substring(startIndex, startIndex + 2));
            }
            if (curr != null && string.startsWith("MAC Address: ")) {
                final int startIndex = "MAC Address: ".length();
                curr.setMac(string.substring(startIndex, startIndex + 17));
                curr.setName(string.substring(startIndex + 19, string.length() - 1));
            }
        }
        return list;
    }
}
